
#include <stdlib.h>
#include <string.h>

#include "VInfra/VDefine.h"
#include "VInfra/VDebug.h"
#include "Json.h"

namespace Veda {


const VJson VJson::null;
const int VJson::minInt = int( ~(int(-1)/2) );
const int VJson::maxInt = int( int(-1)/2 );
const uint VJson::maxUInt = uint(-1);

static VJson null_;


VJson::VJson( JsonValueType type ) : type_( type ), allocated_( false )
{
	switch ( type )
	{
	case nullValue:
		break;
	case intValue:
	case uintValue:
		value_.int_ = 0;
		break;
	case realValue:
		value_.real_ = 0.0;
		break;
	case stringValue:
		value_.string_ = 0;
		break;
	case arrayValue:
	case objectValue:
		value_.map_ = new ObjectValues();
		break;
	case booleanValue:
		value_.bool_ = false;
		break;
	default:
		errorf("VJson constructed by a illegal value type!\n");
		break;
	}
}


VJson::VJson( int value ) : type_( intValue )
{
	value_.int_ = value;
}

VJson::VJson( uint value ) : type_( uintValue )
{
	value_.uint_ = value;
}

VJson::VJson( double value ) : type_( realValue )
{
	value_.real_ = value;
}

VJson::VJson( const char* value ) : type_( stringValue ), allocated_( true )
{
	value_.string_ = valueAllocator()->duplicateStringValue( value );
}

VJson::VJson( const char* beginValue, const char* endValue ) : type_( stringValue ), allocated_( true )
{
	value_.string_ = valueAllocator()->duplicateStringValue( beginValue, uint(endValue - beginValue) );
}

VJson::VJson( const std::string &value ) : type_( stringValue ), allocated_( true )
{
	value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), (uint)value.length() );
}

VJson::VJson( const StaticString &value ) : type_( stringValue ), allocated_( false )
{
	value_.string_ = const_cast<char* >( value.c_str() );
}

VJson::VJson( bool value ) : type_( booleanValue )
{
	value_.bool_ = value;
}

VJson::VJson( const VJson &other ) : type_( other.type_ )
{
	switch ( type_ )
	{
	case nullValue:
	case intValue:
	case uintValue:
	case realValue:
	case booleanValue:
		value_ = other.value_;
		break;
	case stringValue:
		if ( other.value_.string_ )
		{
			value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ );
			allocated_ = true;
		}
		else
			value_.string_ = 0;
		break;
	case arrayValue:
	case objectValue:
		value_.map_ = new ObjectValues( *other.value_.map_ );
		break;
	default:
		errorf("VJson constructed by a illegal value type!\n");
		break;
	}
}

VJson::~VJson()
{
	switch ( type_ )
	{
	case nullValue:
	case intValue:
	case uintValue:
	case realValue:
	case booleanValue:
		break;
	case stringValue:
		if ( allocated_ )
			valueAllocator()->releaseStringValue( value_.string_ );
		break;
	case arrayValue:
	case objectValue:
		delete value_.map_;
		break;
	default:
		errorf("VJson destructed by a illegal value type!\n");
		break;
	}
}

void VJson::swap( VJson& other )
{
	JsonValueType temp = type_;
	type_ = other.type_;
	other.type_ = temp;
	std::swap( value_, other.value_ );
	bool temp2 = allocated_;
	allocated_ = other.allocated_;
	other.allocated_ = temp2;
}

VJson& VJson::operator=( const VJson& other )
{
	VJson temp( other );
	swap( temp );
	return *this;
}

bool VJson::operator <( const VJson& other ) const
{
	int typeDelta = type_ - other.type_;
	if ( typeDelta )
		return typeDelta < 0 ? true : false;
	switch ( type_ )
	{
	case nullValue:
		return false;
	case intValue:
		return value_.int_ < other.value_.int_;
	case uintValue:
		return value_.uint_ < other.value_.uint_;
	case realValue:
		return value_.real_ < other.value_.real_;
	case booleanValue:
		return value_.bool_ < other.value_.bool_;
	case stringValue:
		return (value_.string_ == 0 && other.value_.string_) ||(other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) < 0);
	case arrayValue:
	case objectValue:
		{
			int delta = int( value_.map_->size() - other.value_.map_->size() );
			if ( delta )
				return delta < 0;
			return (*value_.map_) < (*other.value_.map_);
		}
	default:
		errorf("VJson is a illegal value type!\n");
		break;
	}
	return false;  // unreachable
}

bool VJson::operator >( const VJson& other ) const
{
	return other < *this;
}

bool VJson::operator <=( const VJson& other ) const
{
	return !(other > *this);
}

bool VJson::operator >=( const VJson& other ) const
{
	return !(*this < other);
}

bool VJson::operator ==( const VJson& other ) const
{
	int temp = other.type_;
	if ( type_ != temp )
		return false;
	switch ( type_ )
	{
	case nullValue:
		return true;
	case intValue:
		return value_.int_ == other.value_.int_;
	case uintValue:
		return value_.uint_ == other.value_.uint_;
	case realValue:
		return value_.real_ == other.value_.real_;
	case booleanValue:
		return value_.bool_ == other.value_.bool_;
	case stringValue:
		return (value_.string_ == other.value_.string_) || (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) == 0);
	case arrayValue:
	case objectValue:
		return value_.map_->size() == other.value_.map_->size() && (*value_.map_) == (*other.value_.map_);
	default:
		errorf("VJson is a illegal value type!\n");
		break;
	}
	return false;  // unreachable
}

bool VJson::operator !=( const VJson& other ) const
{
	return !( *this == other );
}

bool VJson::isMember( const char *key ) const
{
	const VJson *value = &((*this)[key]);
	return value != &null;
}

bool VJson::isMember( const std::string &key ) const
{
	return isMember( key.c_str() );
}

const char* VJson::asCString() const
{
	if( type_ == stringValue )
		return value_.string_;
	else
		return toStyledString().c_str();
}


std::string VJson::asString() const
{
	switch ( type_ )
	{
	case nullValue:
		return "";
	case stringValue:
		return value_.string_ ? value_.string_ : "";
	case booleanValue:
		return value_.bool_ ? "true" : "false";
	case intValue:
	case uintValue:
	case realValue:
	case arrayValue:
	case objectValue:
			return toStyledString();
	default:
		errorf("VJson is a illegal value type!\n");
		return "";
	}
}

int VJson::asInt() const
{
	switch ( type_ )
	{
	case nullValue:
		return 0;
	case intValue:
		return value_.int_;
	case uintValue:
		if( value_.uint_ < (unsigned)maxInt )
			return value_.uint_;
		else
		{
			warnf("VJson 'asInt' overflow!\n");
			return 0;
		}
	case realValue:
		if( value_.real_ >= minInt  &&  value_.real_ <= maxInt )
			return (int)(value_.real_);
		else
		{
			warnf("VJson 'asInt' overflow!\n");
			return 0;
		}
	case booleanValue:
		return value_.bool_ ? 1 : 0;
	case stringValue:
	case arrayValue:
	case objectValue:
		warnf("VJson 'asInt' used by string, array or object type!\n");
		return 0;
	default:
		errorf("VJson is a illegal value type!\n");
		return 0;
	}
}

uint VJson::asUInt() const
{
	switch ( type_ )
	{
	case nullValue:
		return 0;
	case intValue:
		if( value_.int_ >= 0 )
			return value_.int_;
		else
		{
			warnf("VJson 'asUInt'  used by negative number!\n");
			return 0;
		}
	case uintValue:
		return value_.uint_;
	case realValue:
		if( value_.real_ >= 0  &&  value_.real_ <= maxUInt )
			return (uint)( value_.real_ );
		else
		{
			warnf("VJson 'asUInt'  used by negative number or overflow!\n");
			return 0;
		}
	case booleanValue:
		return value_.bool_ ? 1 : 0;
	case stringValue:
	case arrayValue:
	case objectValue:
		warnf("VJson 'asUInt' used by string, array or object type!\n");
		return 0;
	default:
		errorf("VJson is a illegal value type!\n");
		return 0;
	}
}

double VJson::asDouble() const
{
	switch ( type_ )
	{
	case nullValue:
		return 0.0;
	case intValue:
		return (double)(value_.int_);
	case uintValue:
		return (double)(value_.uint_);
	case realValue:
		return value_.real_;
	case booleanValue:
		return value_.bool_ ? 1.0 : 0.0;
	case stringValue:
	case arrayValue:
	case objectValue:
		warnf("VJson 'asDouble' used by string, array or object type!\n");
		return 0.0;
	default:
		errorf("VJson is a illegal value type!\n");
		return 0.0;
	}
}

bool VJson::asBool() const
{
	switch ( type_ )
	{
	case nullValue:
		return false;
	case intValue:
	case uintValue:
		return value_.int_ != 0;
	case realValue:
		return value_.real_ != 0.0;
	case booleanValue:
		return value_.bool_;
	case stringValue:
		return value_.string_  &&  value_.string_[0] != 0;
	case arrayValue:
	case objectValue:
		return value_.map_->size() != 0;
	default:
		errorf("VJson is a illegal value type!\n");
		return false;
	}
}

JsonValueType VJson::type() const
{
	return type_;
}

bool VJson::isNull() const
{
	return type_ == nullValue;
}

bool VJson::isBool() const
{
	return type_ == booleanValue;
}

bool VJson::isInt() const
{
	return type_ == intValue;
}

bool VJson::isUInt() const
{
	return type_ == uintValue;
}

bool VJson::isIntegral() const
{
	return type_ == intValue || type_ == uintValue || type_ == booleanValue;
}

bool VJson::isDouble() const
{
	return type_ == realValue;
}

bool VJson::isNumeric() const
{
	return isIntegral() || isDouble();
}

bool VJson::isString() const
{
	return type_ == stringValue;
}

bool VJson::isArray() const
{
	return type_ == nullValue || type_ == arrayValue;
}

bool VJson::isObject() const
{
	return type_ == nullValue || type_ == objectValue;
}

bool VJson::isConvertibleTo( JsonValueType other ) const
{
	switch ( type_ )
	{
	case nullValue:
		return true;
	case intValue:
		return ( other == nullValue  &&  value_.int_ == 0 )
				|| other == intValue
				|| ( other == uintValue  && value_.int_ >= 0 )
				|| other == realValue
				|| other == stringValue
				|| other == booleanValue;
	case uintValue:
		return ( other == nullValue  &&  value_.uint_ == 0 )
				|| ( other == intValue  && value_.uint_ <= (unsigned)maxInt )
				|| other == uintValue
				|| other == realValue
				|| other == stringValue
				|| other == booleanValue;
	case realValue:
		return ( other == nullValue  &&  value_.real_ == 0.0 )
				|| ( other == intValue  &&  value_.real_ >= minInt  &&  value_.real_ <= maxInt )
				|| ( other == uintValue  &&  value_.real_ >= 0  &&  value_.real_ <= maxUInt )
				|| other == realValue
				|| other == stringValue
				|| other == booleanValue;
	case booleanValue:
		return ( other == nullValue  &&  value_.bool_ == false )
				|| other == intValue
				|| other == uintValue
				|| other == realValue
				|| other == stringValue
				|| other == booleanValue;
	case stringValue:
		return other == stringValue
				|| ( other == nullValue  &&  (!value_.string_  ||  value_.string_[0] == 0) );
	case arrayValue:
		return other == arrayValue
				||  ( other == nullValue  &&  value_.map_->size() == 0 );
	case objectValue:
		return other == objectValue
				||  ( other == nullValue  &&  value_.map_->size() == 0 );
	default:
		errorf("VJson is a illegal value type!\n");
		return false;
	}
}

uint VJson::size() const
{
	switch ( type_ )
	{
	case nullValue:
	case intValue:
	case uintValue:
	case realValue:
	case booleanValue:
	case stringValue:
		return 0;
	case arrayValue:  // size of the array is highest index + 1
		if ( !value_.map_->empty() )
		{
			ObjectValues::const_iterator itLast = value_.map_->end();
			--itLast;
			return (*itLast).first.index()+1;
		}
		return 0;
	case objectValue:
		return (int)(value_.map_->size());
	default:
		errorf("VJson is a illegal value type!\n");
		return 0;
	}
}

bool VJson::empty() const
{
	if ( isNull() || isArray() || isObject() )
		return size() == 0u;
	else
		return false;
}

void VJson::clear()
{
	switch ( type_ )
	{
	case nullValue:
	case intValue:
	case uintValue:
	case realValue:
	case booleanValue:
	case stringValue:
		break;
	case arrayValue:
	case objectValue:
		value_.map_->clear();
		break;
	default:
		break;
	}
}

void VJson::resize( uint newSize )
{
	if( type_ != nullValue && type_ != arrayValue )
	{
		warnf("VJson 'resize' only used by null or array type!\n");
		return;
	}
	if ( type_ == nullValue )
		*this = VJson( arrayValue );
	uint oldSize = size();
	if ( newSize == 0 )
		clear();
	else if ( newSize > oldSize )
		(*this)[ newSize - 1 ];
	else
	{
		for ( uint index = newSize; index < oldSize; ++index )
			value_.map_->erase( index );
	}
}

VJson& VJson::append( const VJson& value )
{
	return (*this)[size()] = value;
}

VJson& VJson::operator[]( uint index )
{
	if( type_ != nullValue && type_ != arrayValue )
	{
		//warnf("VJson '[%d]' is not exist!\n", index);
		null_ = null;
		return null_;
	}
	if ( type_ == nullValue )
		*this = VJson( arrayValue );
	CZString key( index );
	ObjectValues::iterator it = value_.map_->lower_bound( key );
	if ( it != value_.map_->end() && (*it).first == key )
		return (*it).second;
	ObjectValues::value_type defaultValue( key, null );
	it = value_.map_->insert( it, defaultValue );
	return (*it).second;
}

const VJson& VJson::operator[]( uint index ) const
{
	if( type_ != arrayValue )
	{
		//warnf("VJson '[%d]' is not exist!\n", index);
		return null;
	}
	CZString key( index );
	ObjectValues::const_iterator it = value_.map_->find( key );
	if ( it == value_.map_->end() )
	{
		//warnf("VJson '[%d]' is not exist!\n", index);
		return null;
	}
	return (*it).second;
}

VJson VJson::get( uint index, const VJson& defaultValue ) const
{
	const VJson *value = &((*this)[index]);
	return value == &null ? defaultValue : *value;
}

bool VJson::isValidIndex( uint index ) const
{
	return index < size();
}

VJson& VJson::operator[]( const char *key )
{
	if( type_ != nullValue && type_ != objectValue )
	{
		//warnf("VJson '[\"%s\"]' is not exist!\n", key);
		null_ = null;
		return null_;
	}
	if ( type_ == nullValue )
		*this = VJson( objectValue );
	CZString actualKey( key, CZString::duplicateOnCopy );
	ObjectValues::iterator it = value_.map_->lower_bound( actualKey );
	if ( it != value_.map_->end() && (*it).first == actualKey )
		return (*it).second;
	ObjectValues::value_type defaultValue( actualKey, null );
	it = value_.map_->insert( it, defaultValue );
	VJson& value = (*it).second;
	return value;
}

const VJson& VJson::operator[]( const char *key ) const
{
	if( type_ != objectValue )
	{
		//warnf("VJson '[\"%s\"]' is not exist!\n", key);
		return null;
	}
	CZString actualKey( key, CZString::noDuplication );
	ObjectValues::const_iterator it = value_.map_->find( actualKey );
	if ( it == value_.map_->end() )
	{
		//warnf("VJson '[\"%s\"]' is not exist!\n", key);
		return null;
	}
	return (*it).second;
}

VJson& VJson::operator[]( const std::string& key )
{
	return (*this)[ key.c_str() ];
}

const VJson& VJson::operator[]( const std::string& key ) const
{
	return (*this)[ key.c_str() ];
}

VJson& VJson::operator[]( const StaticString& key )
{
	if( type_ != nullValue && type_ != objectValue )
	{
		//warnf("VJson '[\"%s\"]' is not exist!\n", key.c_str());
		null_ = null;
		return null_;
	}
	if ( type_ == nullValue )
		*this = VJson( objectValue );
	CZString actualKey( key, CZString::noDuplication );
	ObjectValues::iterator it = value_.map_->lower_bound( actualKey );
	if ( it != value_.map_->end() && (*it).first == actualKey )
		return (*it).second;
	ObjectValues::value_type defaultValue( actualKey, null );
	it = value_.map_->insert( it, defaultValue );
	VJson& value = (*it).second;
	return value;
}

VJson VJson::get( const char *key, const VJson& defaultValue ) const
{
	const VJson *value = &((*this)[key]);
	return value == &null ? defaultValue : *value;
}

VJson VJson::get( const std::string &key, const VJson& defaultValue ) const
{
	return get( key.c_str(), defaultValue );
}

VJson VJson::removeMember( const char* key )
{
	if( type_ != objectValue )
	{
		warnf("VJson 'removeMember' only used by object type!\n");
		return null;
	}
	CZString actualKey( key, CZString::noDuplication );
	ObjectValues::iterator it = value_.map_->find( actualKey );
	if ( it == value_.map_->end() )
	{
		//warnf("VJson '[\"%s\"]' is not exist!\n", key);
		return null;
	}
	VJson old(it->second);
	value_.map_->erase(it);
	return old;
}

VJson VJson::removeMember( const std::string &key )
{
	return removeMember( key.c_str() );
}

VJson::Members VJson::getMemberNames() const
{
	if( type_ != objectValue )
	{
		warnf("VJson 'getMemberNames' only used by object type!\n");
		return VJson::Members();
	}
	Members members;
	members.reserve( value_.map_->size() );
	ObjectValues::const_iterator it = value_.map_->begin();
	ObjectValues::const_iterator itEnd = value_.map_->end();
	for ( ; it != itEnd; ++it )
		members.push_back( std::string( (*it).first.c_str() ) );
	return members;
}

std::string VJson::toStyledString() const
{
	VJsonStyledWriter writer;
	return writer.write( *this );
}

VJson::iterator VJson::begin()
{
	switch ( type_ )
	{
	case arrayValue:
	case objectValue:
		if ( value_.map_ )
		return iterator( value_.map_->begin() );
		break;
	default:
		break;
	}
	return iterator();
}

VJson::iterator VJson::end()
{
	switch ( type_ )
	{
	case arrayValue:
	case objectValue:
		if ( value_.map_ )
		return iterator( value_.map_->end() );
		break;
	default:
		break;
	}
	return iterator();
}

VJson::const_iterator VJson::begin() const
{
	switch ( type_ )
	{
	case arrayValue:
	case objectValue:
		if ( value_.map_ )
		return const_iterator( value_.map_->begin() );
		break;
	default:
		break;
	}
	return const_iterator();
}

VJson::const_iterator VJson::end() const
{
	switch ( type_ )
	{
	case arrayValue:
	case objectValue:
		if ( value_.map_ )
		return const_iterator( value_.map_->end() );
		break;
	default:
		break;
	}
	return const_iterator();
}


}

